Last updated: 2025-05-28
Checks: 6 1
Knit directory: /mnt/central_nas/projects/type1_diabetes/nathan/BlockCourse/2024_BlockCourse/T1D_analysis/
This reproducible R Markdown analysis was created with workflowr (version 1.7.1). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
The R Markdown file has unstaged changes. To know which version of the R Markdown file created these results, you’ll want to first commit it to the Git repo. If you’re still working on the analysis, you can ignore this warning. When you’re finished, you can run wflow_publish to commit the R Markdown file and build the HTML.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(12345) was run prior to running the code in the R Markdown file. Setting a seed ensures that any results that rely on randomness, e.g. subsampling or permutations, are reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Great job! Using relative paths to the files within your workflowr project makes it easier to run your code on other machines.
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version 955a62a. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for the analysis have been committed to Git prior to generating the results (you can use wflow_publish or wflow_git_commit). workflowr only checks the R Markdown file, but you know if there are other scripts or data files that it depends on. Below is the status of the Git repository when the results were generated:
Ignored files:
Ignored: T1D_analysis/figure/
Ignored: processing/
Unstaged changes:
Modified: T1D_analysis/01_ImportData_cells_Compressed.html
Modified: T1D_analysis/02_SpilloverCompensation_cells_Compressed.html
Modified: T1D_analysis/03_TransformCorrect_cells_Compressed.html
Modified: T1D_analysis/05_CellCategories_cells_Compressed.Rmd
Modified: T1D_analysis/05_CellCategories_cells_Uncompressed.Rmd
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were made to the R Markdown (T1D_analysis/05_CellCategories_cells_Uncompressed.Rmd) and HTML (T1D_analysis/05_CellCategories_cells_Uncompressed.html) files. If you’ve configured a remote Git repository (see ?wflow_git_remote), click on the hyperlinks in the table below to view the files as they were in that past version.
| File | Version | Author | Date | Message |
|---|---|---|---|---|
| Rmd | 955a62a | nathansteenbuck | 2025-05-28 | full update 2025 annotation |
| Rmd | 35c060e | nathansteenbuck | 2025-05-27 | minor updates pipeline |
| Rmd | 3c04956 | nathansteenbuck | 2024-11-21 | final script added |
| Rmd | f9ec97c | nathansteenbuck | 2024-11-20 | adjust descriptions |
| Rmd | 43dff72 | nathansteenbuck | 2024-11-19 | update analysis_pipeline |
| Rmd | 1f3aba7 | nathansteenbuck | 2024-11-12 | T1D_analysis with uncompressed cell type annotation |
| Rmd | d572272 | nathansteenbuck | 2024-11-11 | T1D_analysis v1 |
In the following scripts, cell types are attributed to all cells in the dataset in an iterative way:
Rscript -e “rmarkdown::render(‘2024_BlockCourse/T1D_analysis/05_CellCategories_cells_Uncompressed.Rmd’)”
05_CellCategories_cells_Uncompressed (this script): Attribution of cell types from the uncompressed dataset.This is performed by performing PhenoGraph clustering using the Rphenoannoy package.
For cell type annotation we perform unsupervised clustering, and then relate the lineage marker expression of clusters to cell types.
The resulting cell categories, which are used in downstream analyses are stored as colData(spe)$cell_type.
suppressPackageStartupMessages(c(
library(data.table),
library(dplyr),
library(SpatialExperiment),
library(parallel),
library(tictoc),
library(purrr),
library(furrr)
))
# Paths
if (!dir.exists(paths$folder_script)) dir.create(paths$folder_script)
plotsave_param$path <- paths$folder_script
plotsave_param_large$path <- paths$folder_script
# Misc settings
today <- gsub("-", "", Sys.Date())
Load the SpatialExperiment (SPE) object saved at the previous step.
fn_spe <- file.path(paths$folder_out, paste0(paths$object_type, "_", paths$panel_type, ".rds"))
spe <- readRDS(fn_spe)
print(spe)
class: SpatialExperiment
dim: 31 83537
metadata(1): spillover_matrix
assays(6): counts compcounts ... scaled fastMNN_case_id
rownames(31): H3 SST ... DNA1 PPY
rowData names(13): channel metal ... ...12 channel_name
colnames(83537): 6238_Uncompressed_001_1 6238_Uncompressed_001_2 ...
6396_Uncompressed_030_775 6396_Uncompressed_030_776
colData names(30): case_id panel ... HbA1c C_peptide
reducedDimNames(0):
mainExpName: NULL
altExpNames(0):
spatialCoords names(2) : cell_x cell_y
imgData names(1): sample_id
imgloader <- function(x, image_dir, image_names,
suffix_rem = "", suffix_add = "",
bit_depth = 16, type, ...) {
require(cytomapper)
image_list <- file.path(image_dir, image_names)
# Test if the image list exist
test_exist <- which(!file.exists(image_list))
if (length(test_exist) > 0) {
stop(c("The following images were not found:\n",
paste(image_list[test_exist], collapse = "\n")))
} else {
# Load and scale the images
images <- loadImages(image_list, ...)
# images <- scaleImages(images, (2 ^ bit.depth) - 1)
# Add image names to metadata
mcols(images)$ImageName <- gsub(suffix_rem, "", names(images))
mcols(images)$ImageName <- paste0(mcols(images)$ImageName, suffix_add)
# Add channel names
if (type == "stacks") {
print("Loading image stacks")
channelNames(images) <- rownames(x)
}
return(images)
}
}
RPhenoannoy can installed with: devtools::install_github("stuchly/Rphenoannoy@8b81e2e7fb0599f45070e2cba1b28ac219b7c472")
suppressPackageStartupMessages(c(
library(ggplot2),
library(scater),
library(scuttle),
library(scran),
library(igraph),
library(Rphenoannoy),
library(clustree),
library(ranger),
library(patchwork),
library(BiocParallel),
library(tictoc)
))
Select channels (channels_clust), assays (assay_sel) and clustering methods (methods_sel) to use.
methods_sel <- c("Pheno1")
assay_sel <- c("scaled")
names(assay_sel) <- c("scaled")
writeLines(c("Assays:", assay_sel[assay_sel %in% assayNames(spe)],
assay_sel[assay_sel %in% reducedDimNames(spe)]))
Assays:
scaled
dimred_sel <- c("UMAP")
writeLines(c("\nReduced dimensions:", dimred_sel))
Reduced dimensions:
UMAP
channels <- rownames(spe)[!(grepl("DNA|H3", rownames(spe)))]
cat(c("\nChannels:", channels[channels %in% rownames(spe)]))
Channels: SST INS CD44 GLUT1 CD99 CD68 MPO SMA CD20 AMY CD3e CK19 ProINS GCG PDX1 SYP CD45RO FOXP3 CD45RA CD8a CA9 IAPP NKX6_1 CD4 CD31 Ecdh PTPRN PCSK2 PPY
cat(c("\nNumber of channels:", length(channels)))
Number of channels: 29
Reduced dimension plots showing marker expression that generated by the previous script can be used to select the most relevant markers for clustering.
channels_clust <- rownames(rowData(spe)[rowData(spe)$clustering == 1, ])
cat(c("\nChannels used for unsupervised clustering:",
channels_clust[channels_clust %in% rownames(spe)]))
Channels used for unsupervised clustering: SST INS CD44 GLUT1 CD99 CD68 MPO SMA CD20 AMY CD3e CK19 ProINS GCG PDX1 SYP CD45RO FOXP3 CD45RA CD8a CA9 IAPP NKX6_1 CD4 CD31 Ecdh PTPRN PCSK2 PPY
# Extract the metadata (to avoid conflicts when merging the SCEs)
meta <- metadata(spe)
spatial_coords <- spatialCoords(spe)
colpairs <- colPairs(spe)
# Convert to SingleCellExperiment
sce <- as(spe, "SingleCellExperiment")
remove(spe)
Unsupervised clustering is performed with the PhenoGraph algorithm. This method works by generating a nearest-neighbor (kNN) graph of phenotpyic similarities followed by Louvain community dectection.
Here, we try the Rphenoannoy implementation. RPhenoannoy implements a parallel Jaccard-coefficient, approximates the kNN and uses Louvain clustering.
clust_method <- c("Pheno1")
# Number of nearest-neighbors
k <- 30
cur_assay <- "scaled"
# Run Phenograph - PhenoGraph for exprs and scaled assay.
clust_name <- paste(clust_method, cur_assay, sep = "_")
writeLines(c("\n", clust_name))
Pheno1_scaled
if (!clust_name %in% colnames(colData(sce))) {
set.seed(seed)
# Run Rphenograph.
cur_pheno_annoy <- Rphenoannoy::Rphenoannoy(t(assay(sce, cur_assay))[, channels_clust], k = k)
cur_pheno <- DataFrame(cur_pheno_annoy[[2]]$membership)
colnames(cur_pheno) <- clust_name
rownames(cur_pheno) <- colnames(assay(sce, cur_assay))
# Add Phenograph clusters to the colData of the SCE object
# Cluster `0` is attributed to non-subsetted cells and not islet cells
colData(sce)[, clust_name] <- cur_pheno
remove(cur_pheno)
}
Run Rphenograph starts:
-Input data of 83537 rows and 29 columns
-k is set to 30
Finding nearest neighbors...DONE ~ 20.918 s
Compute jaccard coefficient between nearest-neighbor sets...
Presorting knn...
presorting DONE ~ 3.946 s
Start jaccard
DONE ~ 0.109 s
Build undirected graph from the weighted links...DONE ~ 2.42 s
Run louvain clustering on the graph ...DONE ~ 30.638 s
Run Rphenograph DONE, totally takes 54.085s.
Return a community class
-Modularity value: 0.8468253
-Number of clusters: 26
suppressPackageStartupMessages(c(
library(heatmaply),
library(htmltools)#,
#library(cytomapper)
))
RUN UMAP again.
set.seed(222)
if (!("subset" %in% names(metadata(sce)))) {
# Cells per case
nb_cells <- 7500
# Subset the SPE object (nb_cells per case)
cell_subset <- tibble(rn = rownames(colData(sce)),
case_id = colData(sce)$case_id) |>
group_by(case_id) |>
sample_n(nb_cells) |>
pull(rn)
# Keep the subset cell ids in SPE metadata
metadata(sce)[["subset"]] <- sort(as.vector(cell_subset))
}
# Keep only the selected cells and channels
spe_sub <- sce[channels_clust, metadata(sce)[["subset"]]]
# Add UMAPs to SPE object
cur_assay <- "scaled"
dimred_name <- paste("UMAP", cur_assay, sep = "_")
print(dimred_name)
[1] "UMAP_scaled"
# Run UMAP on a cell subset
if ((!dimred_name %in% reducedDimNames(spe_sub)) && ("UMAP" %in% dimred_sel)) {
# Extract Counts.
if (cur_assay %in% assayNames(spe_sub)) {
counts <- t(assay(spe_sub, cur_assay))
}
# Run UMAP.
umap_model <- uwot::umap(counts, ret_model = TRUE)
# Extract Embedding.
cur_umap <- umap_model$embedding
colnames(cur_umap) <- c("UMAP1", "UMAP2")
rownames(cur_umap) <- rownames(counts)
}
reducedDim(spe_sub, dimred_name) <- cur_umap
cur_method <- "Pheno1"
cur_dimred <- "UMAP"
cur_dat <- makePerCellDF(spe_sub, use_dimred = TRUE) |>
dplyr::arrange(case_id, donor_type) |>
tibble::as_tibble()
dimred_name <- paste(cur_dimred, cur_assay, sep = "_")
clust_name <- paste(cur_method, cur_assay, sep = "_")
# Plot all clustersdat, dimred, color_by
p <- plot_dim_red(dat = cur_dat, dimred = dimred_name, color_by = clust_name,
sample = TRUE, size = 0.1, alpha = 1)
print(p)
fn <- paste0(paste(today, "Clusters", clust_name, cur_dimred,
sep = "_"), ".png")
do.call(ggsave, c(list(fn, p), plotsave_param))
name_cur_assay <- "scaled"
clust_name <- paste(cur_method, cur_assay, sep = "_")
message(clust_name)
Pheno1_scaled
channels_clust2 <- channels_clust[!channels_clust %in% c("Rb", "FOXP3", "PTPRN", "CD20")]
# Summarize the data
hm <- summarize_heatmap(sce,
expr_values = name_cur_assay,
cluster_by = clust_name,
channels = channels_clust2)
# Display the heatmap
fn <- paste0(paste(today, "Clusters", clust_name, "Heatmap",
sep = "_"), ".html")
heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
# remove all clusters with less than 10 cells and plot again.
clust_freq <- table(colData(sce)[[clust_name]])
clust_freq
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
7906 7420 2527 5728 8678 7237 2997 3035 6104 2416 945 130 2558 3271 4309 5161
17 18 19 20 21 22 23 24 25 26
4397 2808 817 276 359 192 1665 287 1311 1003
Rare Clusters: 12, 24, 21, 22 (all below 200).
Here, we use the cytoviewer package to visualize the clusters on the images. Thereby, we can check if the clusters are biologically meaningful and if they indeed correspond to the respective cell types.
Additional information we can use is their spatial localization of cell types, i.e. which cells in the endocrine or exocrine compartment.
# viz_clust <- c(26, 23, 12) # Select cluster(s) to visualize.
viz_clust <- NULL
viz_method <- "Pheno1"
viz_assay <- "scaled"
if (!is.null(viz_clust)) {
nb_images <- 14
image_extension <- ".tiff"
clust_name <- paste(viz_method, viz_assay, sep = "_")
# Subset the SCE
sce_viz <- sce[, colData(sce)[[clust_name]] %in% viz_clust]
# Select random image.
set.seed(seed)
image_sub <- sort(sample(
unique(sce_viz$image_fullname),
min(length(unique(sce_viz$image_fullname)), nb_images)))
# Folders
folder_images <- file.path(paths$folder_in, "img", paths$panel_type)
folder_masks <- file.path(paths$folder_in, "masks_cells",
paths$panel_type, "whole-cell")
# Load images and masks
images <- imgloader(
x = sce_viz,
image_dir = folder_images,
image_names = image_sub,
type = "stacks"
)
masks <- imgloader(
x = sce_viz,
image_dir = folder_masks,
image_names = image_sub,
as.is = TRUE,
type = "masks"
)
sce_viz <- sce_viz[, sce_viz$image_fullname %in% image_sub]
sce_viz$ImageName <- gsub(image_extension, "", sce_viz$image_fullname)
}
# Use cytoviewer with images, masks and object
library(cytoviewer)
if (!is.null(viz_clust)) {
channels_view <- channels_clust
sub_images <- cytomapper::getChannels(images, channels_view)
app <- cytoviewer(image = sub_images,
mask = masks,
object = sce_viz[channels_view, ],
img_id = "ImageName",
cell_id = "cell_number")
if (interactive()) {
shiny::runApp(app)
}
}
Note: this section requires manual intervention
Here, clusters obtained at the previous steps are manually merged into meaningful cell types. Cluster numbers are attributed to the different cell types based on the plots and heatmaps above. Consequently, this attribution has to be adapted to the clustering results.
Cell category attribution has to be performed for every combination of clustering methods and selected assays.
Depending on the clustering, maybe select other categories.
clust_methods <- c("Pheno1")
clust_assay <- c("scaled")
if (!clust_assay %in% assay_sel) stop("The selected assay is not in the assays selected for clustering")
if (length(clust_assay) != 1) ("Select only one assay")
clust_name <- paste(clust_methods, clust_assay, sep = "_")
print(clust_name)
[1] "Pheno1_scaled"
# Islet:
clust_beta <- c(15, 14) #
clust_alpha <- c(16, 24)
clust_delta <- c(18)
clust_gamma <- c(12)
clust_islet_other <- c(13) #
# Immune:
clust_t <- c(11)
clust_neutrophil <- c(22)
clust_myeloid <- c(20)
# Exocrine Cells + Stromal.
clust_endothelial <- c(7)
clust_mesenchymal <- c(21)
clust_ductal <- c(9, 1, 17, 19)
clust_acinar <- c(26, 2:6, 8)
clust_other <- c(10, 23, 25)
all_clust <- sort(c(clust_alpha, clust_beta, clust_delta, clust_gamma, clust_islet_other,
clust_t, clust_neutrophil, clust_myeloid,
clust_endothelial, clust_mesenchymal,
clust_ductal, clust_acinar, clust_other))
if ((!length(unique(all_clust)) ==
length(unique(colData(sce)[, clust_name]))) ||
any(duplicated(all_clust))) {
stop("Recheck cluster attribution")
}
# Add cell types to the SCE object
# Islet
colData(sce)[colData(sce)[, clust_name] %in% clust_alpha,
"cell_type"] <- "Alpha"
colData(sce)[colData(sce)[, clust_name] %in% clust_beta,
"cell_type"] <- "Beta"
colData(sce)[colData(sce)[, clust_name] %in% clust_delta,
"cell_type"] <- "Delta"
colData(sce)[colData(sce)[, clust_name] %in% clust_gamma,
"cell_type"]<- "Gamma"
colData(sce)[colData(sce)[, clust_name] %in% clust_islet_other,
"cell_type"] <- "Islet_Other"
# Immune:
colData(sce)[colData(sce)[, clust_name] %in% clust_t,
"cell_type"] <- "T_cell"
colData(sce)[colData(sce)[, clust_name] %in% clust_myeloid,
"cell_type"] <- "Myeloid"
colData(sce)[colData(sce)[, clust_name] %in% clust_neutrophil,
"cell_type"] <- "Neutrophil"
# Exocrine
colData(sce)[colData(sce)[, clust_name] %in% clust_ductal,
"cell_type"] <- "Ductal"
colData(sce)[colData(sce)[, clust_name] %in% clust_acinar,
"cell_type"] <- "Acinar"
# Stroma:
colData(sce)[colData(sce)[, clust_name] %in% clust_endothelial,
"cell_type"] <- "Endothelial"
colData(sce)[colData(sce)[, clust_name] %in% clust_mesenchymal,
"cell_type"] <- "Fibro_SM"
# Other
colData(sce)[colData(sce)[, clust_name] %in% clust_other,
"cell_type"] <- "Other"
Assign Cell Categories base don the assigned cell types.
# Islet-category (Alpha, Beta, Delta, Gamma)
colData(sce)[colData(sce)[, "cell_type"] %in% c("Alpha", "Beta", "Delta", "Gamma", "Islet_Other"),
"cell_category"] <- "Islet"
# Immune-category (Lympho, Myeloid, Neutrophil)
colData(sce)[colData(sce)[, "cell_type"] %in% c("T_cell", "Myeloid", "Neutrophil"),
"cell_category"] <- "Immune"
# Exocrine-category (Ductal, Acinar)
colData(sce)[colData(sce)[, "cell_type"] %in% c("Ductal", "Acinar"),
"cell_category"] <- "Exocrine"
# Stroma-category (Endothelial, Fibro_Endo)
colData(sce)[colData(sce)[, "cell_type"] %in% c("Endothelial", "Fibro_SM"),
"cell_category"] <- "Stroma"
# Other-category (Other)
colData(sce)[colData(sce)[, "cell_type"] %in% c("Other"),
"cell_category"] <- "Other"
spe_sub$Pheno1_scaled <- sce[, colnames(spe_sub)]$Pheno1_scaled
spe_sub$cell_type <- sce[, colnames(spe_sub)]$cell_type
# Prepare the data
cur_dat <- makePerCellDF(spe_sub, use_dimred = TRUE) |>
arrange(case_id, donor_type)
# Plot
cur_assay <- "scaled"
cur_dimred <- "UMAP"
cur_method <- "Pheno1"
dimred_name <- paste(cur_dimred, cur_assay, sep = "_")
clust_name <- "cell_type"
p <- plot_dim_red(cur_dat, dimred_name, clust_name,
sample = TRUE, size = 1, alpha = 1)
print(p)
fn <- paste0(paste(today, clust_name, cur_dimred,
sep = "_"), ".png")
do.call(ggsave, c(list(fn, p), plotsave_param))
channels_clust2 <- channels_clust[!channels_clust %in%
c("Rb", "FOXP3", "CD45RA", "PTPRN", "CD20")]
cur_assay <- "scaled"
name_cur_assay <- "scaled"
clust_name <- "cell_type"
# Summarize the data
hm <- summarize_heatmap(sce,
expr_values = name_cur_assay,
cluster_by = clust_name,
channels = channels_clust2)
# Display the heatmap
fn <- paste0(paste(today, clust_name, "Heatmap",
sep = "_"), ".html")
set.seed(222)
heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
table(colData(sce)[, "cell_type"])
Acinar Alpha Beta Delta Ductal Endothelial
35628 5448 7580 2808 19224 2997
Fibro_SM Gamma Islet_Other Myeloid Neutrophil Other
359 130 2558 276 192 5392
T_cell
945
table(colData(sce)[, "cell_category"])
Exocrine Immune Islet Other Stroma
54852 1413 18524 5392 3356
Plot consensus cell categories on reduced dimensions
spe_sub$cell_category <- sce[, colnames(spe_sub)]$cell_category
ccat <- c("Immune", "Islet", "Exocrine", "Stroma", "Other")
names(ccat) <- c("Immune", "Islet", "Exocrine", "Stroma", "Other")
palette_ccat <- c(palettes$colors[1:(length(ccat) - 2)], "grey40", "grey")
names(palette_ccat) <- ccat
cur_dat <- scuttle::makePerCellDF(spe_sub,
use_dimred = TRUE) |>
arrange(case_id, donor_type)
dimred_name <- paste(cur_dimred, cur_assay, sep = "_")
p <- plot_dim_red(cur_dat, dimred_name, "cell_category",
sample = TRUE, size = 0.1, alpha = 1,
palette = palette_ccat)
print(p)
fn <- paste0(paste(today, "CellCat", "Consensus", dimred_name,
sep = "_"), ".png")
do.call(ggsave, c(list(fn, p), plotsave_param))
clust_name <- paste("cell_category", cur_assay, sep = "_")
# Summarize the data
hm <- summarize_heatmap(sce,
expr_values = cur_assay,
cluster_by = "cell_category",
channels = channels)
# Display the heatmap
fn <- paste0(paste(today, "CellCat", "Consensus", cur_assay,
"Heatmap", sep = "_"), ".html")
heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
fn <- file.path(paths$folder_out, paste0(paths$object_type, "_", paths$panel_type, "sce.rds"))
saveRDS(sce, fn)
sessionInfo()
R version 4.3.1 (2023-06-16)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.6 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
locale:
[1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
[4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
time zone: Etc/UTC
tzcode source: system (glibc)
attached base packages:
[1] parallel stats4 stats graphics grDevices utils datasets
[8] methods base
other attached packages:
[1] cytoviewer_1.2.0 htmltools_0.5.8.1
[3] heatmaply_1.5.0 viridis_0.6.5
[5] viridisLite_0.4.2 plotly_4.10.4
[7] BiocParallel_1.36.0 patchwork_1.2.0
[9] ranger_0.16.0 clustree_0.5.1
[11] ggraph_2.2.1 Rphenoannoy_0.1.0
[13] Matrix_1.6-5 igraph_2.1.4
[15] scran_1.30.2 scater_1.30.1
[17] scuttle_1.12.0 furrr_0.3.1
[19] future_1.49.0 purrr_1.0.2
[21] tictoc_1.2.1 data.table_1.17.2
[23] SpatialExperiment_1.12.0 SingleCellExperiment_1.24.0
[25] SummarizedExperiment_1.32.0 Biobase_2.62.0
[27] GenomicRanges_1.54.1 GenomeInfoDb_1.38.8
[29] IRanges_2.36.0 S4Vectors_0.40.2
[31] BiocGenerics_0.48.1 MatrixGenerics_1.14.0
[33] matrixStats_1.5.0 dplyr_1.1.4
[35] ggplot2_3.5.1
loaded via a namespace (and not attached):
[1] RcppAnnoy_0.0.22 later_1.3.2
[3] bitops_1.0-9 svgPanZoom_0.3.4
[5] tibble_3.2.1 polyclip_1.10-7
[7] lifecycle_1.0.4 edgeR_4.0.16
[9] rprojroot_2.0.4 globals_0.18.0
[11] lattice_0.22-7 MASS_7.3-60
[13] crosstalk_1.2.1 dendextend_1.17.1
[15] magrittr_2.0.3 limma_3.58.1
[17] sass_0.4.9 rmarkdown_2.27
[19] jquerylib_0.1.4 yaml_2.3.10
[21] metapod_1.10.1 httpuv_1.6.15
[23] sp_2.1-4 RColorBrewer_1.1-3
[25] abind_1.4-8 zlibbioc_1.48.2
[27] RCurl_1.98-1.14 tweenr_2.0.3
[29] git2r_0.33.0 seriation_1.5.5
[31] GenomeInfoDbData_1.2.11 ggrepel_0.9.5
[33] irlba_2.3.5.1 listenv_0.9.1
[35] terra_1.7-78 dqrng_0.4.1
[37] parallelly_1.44.0 svglite_2.1.3
[39] DelayedMatrixStats_1.24.0 codetools_0.2-20
[41] DelayedArray_0.28.0 ggforce_0.4.2
[43] tidyselect_1.2.1 raster_3.6-26
[45] farver_2.1.2 ScaledMatrix_1.10.0
[47] TSP_1.2-4 webshot_0.5.5
[49] jsonlite_2.0.0 BiocNeighbors_1.20.2
[51] tidygraph_1.3.1 iterators_1.0.14
[53] systemfonts_1.1.0 foreach_1.5.2
[55] tools_4.3.1 ragg_1.3.2
[57] Rcpp_1.0.14 glue_1.8.0
[59] gridExtra_2.3 SparseArray_1.2.4
[61] xfun_0.52 EBImage_4.44.0
[63] HDF5Array_1.30.1 ca_0.71.1
[65] shinydashboard_0.7.2 withr_3.0.2
[67] fastmap_1.2.0 rhdf5filters_1.14.1
[69] bluster_1.12.0 fansi_1.0.6
[71] digest_0.6.37 rsvd_1.0.5
[73] R6_2.6.1 mime_0.13
[75] textshaping_0.4.0 colorspace_2.1-1
[77] jpeg_0.1-11 utf8_1.2.5
[79] tidyr_1.3.1 generics_0.1.4
[81] graphlayouts_1.1.1 httr_1.4.7
[83] htmlwidgets_1.6.4 S4Arrays_1.2.1
[85] whisker_0.4.1 uwot_0.2.2
[87] pkgconfig_2.0.3 gtable_0.3.6
[89] registry_0.5-1 workflowr_1.7.1
[91] XVector_0.42.0 fftwtools_0.9-11
[93] scales_1.3.0 png_0.1-8
[95] knitr_1.47 reshape2_1.4.4
[97] rjson_0.2.23 rhdf5_2.46.1
[99] cachem_1.1.0 stringr_1.5.1
[101] shinycssloaders_1.0.0 miniUI_0.1.1.1
[103] vipor_0.4.7 pillar_1.9.0
[105] grid_4.3.1 vctrs_0.6.5
[107] RANN_2.6.2 promises_1.3.0
[109] BiocSingular_1.18.0 beachmat_2.18.1
[111] xtable_1.8-4 cluster_2.1.8.1
[113] archive_1.1.12 beeswarm_0.4.0
[115] evaluate_1.0.3 magick_2.8.3
[117] cli_3.6.5 locfit_1.5-9.9
[119] compiler_4.3.1 rlang_1.1.6
[121] crayon_1.5.3 labeling_0.4.3
[123] plyr_1.8.9 fs_1.6.6
[125] ggbeeswarm_0.7.2 stringi_1.8.7
[127] nnls_1.6 cytomapper_1.14.0
[129] assertthat_0.2.1 munsell_0.5.1
[131] tiff_0.1-12 lazyeval_0.2.2
[133] colourpicker_1.3.0 sparseMatrixStats_1.14.0
[135] Rhdf5lib_1.24.2 statmod_1.5.0
[137] shiny_1.8.1.1 highr_0.11
[139] memoise_2.0.1 bslib_0.7.0